WPF: Data Templates


This entry is about creating Data Templates. A data template is basically a template that lets you define the visual structure of a control. With a data template you can change the look and feel of any control, typically in container controls like ListBox and ItemsControl (controls that hold a collection of items). This is when data templates are utilized to it’s full potential.

In this post, I have created a pseudo business application that allows you to select a product and quantity, and add that to a ListBox re-defined with a data template. This is what it looks like.

wpf_datatemplate

In this sample, I have used 2 data templates for the ListBoxItem, a normal template and one for when then ListBoxItem is selected. If you look at the screenshot, when the item is selected, you see more details and a “delete button”, whereas the others have a default look. Here’s the Xaml for the default data template.

<DataTemplate x:Key="ListBoxItemTemplate" DataType="{x:Type local:Product}">
 <Grid>
 <Grid.RowDefinitions>
 <RowDefinition />
 </Grid.RowDefinitions>
 <Grid.ColumnDefinitions>
 <ColumnDefinition Width="*" />
 <ColumnDefinition Width="Auto" />
 </Grid.ColumnDefinitions>

 <TextBlock Text="{Binding Name}" FontWeight="Bold"  Grid.Column="0" Grid.Row="0" Margin="5" />
 <TextBlock Text="{Binding Path=QtyOrdered, StringFormat=Quantity: \{0\}}" 
      Grid.Column="1" Grid.Row="0" Margin="5" />

 </Grid>
</DataTemplate>

Here’s the Xaml for the ListBoxItem‘s Selected data template.

<DataTemplate x:Key="SelectedListBoxItemTemplate" DataType="{x:Type local:Product}">
 <Grid>
 <Grid.RowDefinitions>
 <RowDefinition />
 <RowDefinition />
 </Grid.RowDefinitions>
 <Grid.ColumnDefinitions>
 <ColumnDefinition Width="*" />
 <ColumnDefinition Width="Auto" />
 <ColumnDefinition Width="Auto" />
 </Grid.ColumnDefinitions>

 <StackPanel Grid.Column="0" Grid.Row="0" Orientation="Vertical" >
 <TextBlock Text="Name" FontWeight="Bold" />
 <TextBlock Margin="10,0,0,0" >
 <TextBlock.Text>
 <MultiBinding StringFormat="{}{0} (Model Number: {1})" >
 <Binding Path="Name" />
 <Binding Path="ModelNo" />
 </MultiBinding>
 </TextBlock.Text>
 </TextBlock>
 </StackPanel>

 <StackPanel Grid.Column="0" Grid.Row="1" Orientation="Vertical" >
 <TextBlock Text="Description" FontWeight="Bold" />
 <TextBlock Text="{Binding Path=Description}" Margin="10,0,0,0"  />
 </StackPanel>

 <StackPanel Grid.Column="1" Grid.RowSpan="3" Orientation="Horizontal"
 HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,5,0" >
 <TextBlock Text="Quantity: " />
 <TextBlock Text="{Binding Path=QtyOrdered}" />
 </StackPanel>

 <Button Grid.Column="2" Grid.RowSpan="3" Command="Delete" CommandParameter="{Binding}"
 HorizontalAlignment="Center" VerticalAlignment="center" Margin="5">
 <Button.Content>
 <Image Source="/WPFDataTemplate;component/delete-128x128.png" Width="32" Height="32" />
 </Button.Content>
 </Button>
 </Grid>
</DataTemplate>

Now that we have our 2 data templates defined, we have to hook them up to the ListBox. What I’ve done is define a Style (as a resource) and used Style Triggers to set our data templates. The default data template is set as a style setter, and the selected data template is set on the style trigger for “IsSelected” property. Below is a snippet of the style.

<Style x:Key="ListBoxItemContainerStyle" TargetType="{x:Type ListBoxItem}">
 <Setter Property="ContentTemplate" Value="{StaticResource ListBoxItemTemplate}" />
 <Setter Property="HorizontalContentAlignment" Value="Stretch" />
 <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, 
      Path=(ItemsControl.AlternationIndex), Converter={StaticResource BackgroundAlternationConverter}}" />
 <Style.Triggers>
 <Trigger Property="IsSelected" Value="true">
 <Setter Property="ContentTemplate" Value="{StaticResource SelectedListBoxItemTemplate}" />
 </Trigger>
 </Style.Triggers>
</Style>

Last of all, you just have to set the ListBox‘s ItemContainerStyle to the style defined in our resources, like so.


How to set Alternating Background for ListBox

On a side note, something of interest would be how to set alternating background color for the ListBox as seen in the screenshot. Since ListBox derives from an ItemsControl, there’s a property you can use called ItemsControl.AlternationCount property. Used together with ItemsControl.AlternatingIndex (a Static DependencyProperty), and a AlternationConverter, you can create alternating backgrounds for the ListBox, like so.

<AlternationConverter x:Key="BackgroundAlternationConverter">
 <SolidColorBrush>AliceBlue</SolidColorBrush>
 <SolidColorBrush>LightBlue</SolidColorBrush>
</AlternationConverter>

<!--  set this in your <Style> resource -->
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, 
    Path=(ItemsControl.AlternationIndex), Converter={StaticResource BackgroundAlternationConverter}}" />

There we have it, a straightforward, fun and efficient way to make use of data templates to tweak visual appearances and perform data-binding to our data models. Happy Coding.

Download the sample solution here.

Share this post:
Posted in WPF. 1 Comment »

One Response to “WPF: Data Templates”

  1. WPF: Control Templating « Code Blitz Says:

    […] the ability to change the look of any control, and still keeping its original functionality. In my previous blog post, I talked about how create Data Templates. This post, we are going to explore the world of Control […]


Leave a comment